package com.quick.proxy.core.handler;

import com.quick.proxy.core.ChannelAttribute;
import com.quick.proxy.core.CmdTypeConstants;
import com.quick.proxy.core.ProxyMessage;
import com.quick.proxy.core.utils.ByteUtils;
import com.quick.proxy.core.utils.ProtocolUtils;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * Description: 心跳处理程序
 * Author: 吃素不吃肉
 * Date: 2023/7/4
 *
 * @author 吃素不吃肉
 */
@Slf4j
@Sharable
@Component
public class HeartBeatHandler extends ChannelInboundHandlerAdapter {
    /**
     * 空闲次数
     */
    private int idleCount;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //如果是心跳就去除
        idleCount = 0;
        ProxyMessage proxyMessage = (ProxyMessage) msg;
        if (ByteUtils.intToHex(CmdTypeConstants.HEART_BEAT, 1).equals(proxyMessage.getCmdType())) {
            ReferenceCountUtil.release(msg);
        } else {
            super.channelRead(ctx, msg);
        }
    }

    /**
     * 心跳机制
     *
     * @param ctx 上下文
     * @param evt 事件
     * @throws Exception 异常
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.ALL_IDLE && ctx.channel().isActive()) {
                if (idleCount >= 10) {
                    log.warn("accessKey[{}]If the number of idle connections exceeds 10, actively disconnect the connection", ctx.channel().attr(ChannelAttribute.ACCESS_KEY_PROXY_CHANNEL).get());
                    ctx.channel().close();
                } else {
                    idleCount++;
                    ctx.channel().writeAndFlush(ProtocolUtils.getByte(CmdTypeConstants.HEART_BEAT, ByteUtils.hexToBytes(ByteUtils.intToHex(0xFFFF, 2))));
                }
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
